<template>
    <div :class="isShow ? '' : 'hide'" id="webGl"></div>
    <button @click="clickBtn">显示</button>
</template>

<script setup>
import { ref } from 'vue'
import * as THREE from 'three';
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
//引入性能监视器stats.js
import Stats from 'three/addons/libs/stats.module.js';
// 引入dat.gui.js的一个类GUI
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

// 三维场景Scene  ！！！！！！！！！！
const scene = new THREE.Scene(); // 创建3D场景对象Scene
// 物体形状：几何体Geometry  
//BoxGeometry：长方体
const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry：球体
// const geometry = new THREE.SphereGeometry(50);
// CylinderGeometry：圆柱
// const geometry = new THREE.CylinderGeometry(50,50,100);
// PlaneGeometry：矩形平面
// const geometry = new THREE.PlaneGeometry(100,50);
// CircleGeometry：圆形平面
// const geometry = new THREE.CircleGeometry(50);

// 物体外观：材质Material 材质半透明设置
const material = new THREE.MeshPhongMaterial({ // 创建一个材质对象Material，材质
    color: 0x0000ff, //设置材质颜色
    
    // transparent:true,//开启透明
    // opacity:0.5,//设置透明度
    // side:THREE.DoubleSide, //两面可见
    shininess:50, //高光部分的亮度，默认30
    specular: 0x444444, //高光部分的颜色
});

// 物体：网格模型Mesh
// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material)

// 模型位置.position
mesh.position.set(0, 0, 0); //设置网格模型在三维空间中的位置坐标，默认是坐标原点

// .add()方法 把网格模型mesh添加到三维场景scene中
scene.add(mesh)

// for (let i = 0; i < 3; i++) {
//     for (let j = 0; j < 3; j++) {
//         const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//         // 在XOZ平面上分布
//         mesh.position.set(i * 200, 0, j * 200);
//         scene.add(mesh); //网格模型添加到场景中  
//     }
// }
// 随机创建大量的模型,测试渲染性能
const num = 10; //控制长方体模型数量
for (let i = 0; i < num; i++) {
    const geometry = new THREE.BoxGeometry(5, 5, 5);
    const material = new THREE.MeshLambertMaterial({
        color: 0x00ffff
    });
    const mesh = new THREE.Mesh(geometry, material);
    // 随机生成长方体xyz坐标
    const x = (Math.random() - 0.5) * 200
    const y = (Math.random() - 0.5) * 200
    const z = (Math.random() - 0.5) * 200
    mesh.position.set(x, y, z)
    scene.add(mesh); // 模型对象插入场景中
}
// AxesHelper：辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(300);
scene.add(axesHelper);

// 点光源 
//点光源：两个参数分别表示光源颜色和光照强度
// 参数1：0xffffff是纯白光,表示光源颜色
// 参数2：1.0,表示光照强度，可以根据需要调整
const pointLight = new THREE.PointLight(0xffffff, 1.0);

// 光源衰减
pointLight.decay = 0.0;//设置光源不随距离衰减

// 光源位置
pointLight.position.set(100, 60, 50);
// pointLight.position.set(400, 200, 300);//点光源放在x轴上

// 第二个光源
// const pointLight2 = new THREE.PointLight(0xffffff, 1.0);
// pointLight2.decay = 0.0;
// pointLight2.position.set(-400, -200, -300);

// 光源添加到场景
// scene.add(pointLight);

// 光源辅助观察
const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);
// scene.add(pointLightHelper);

//环境光:没有特定方向，整体改变场景的光照明暗
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);

// 平行光DirectionalLight
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(80,100,50) // 设置光源的方向：通过光源position属性和目标指向对象的position属性计算
// directionalLight.target = mesh // 方向光指向对象网格模型mesh，可以不设置，默认的位置是0,0,0
directionalLight.target.position.set(10,0,0)
scene.add(directionalLight)

// 平行光辅助观察DirectionalLightHelper
const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5, 0x00ff00)
scene.add(directionalLightHelper)

// 透视投影相机PerspectiveCamera ！！！！！！！！！！！！
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = 800; //宽度
const height = 500; //高度
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000); // 实例化一个透视投影相机对象

// 相机位置.position 
camera.position.set(800, 800, 800) //相机在Three.js三维坐标系中的位置 根据需要设置相机位置具体值

// 相机观察目标.lookAt()
camera.lookAt(0, 0, 0); // 坐标原点
// camera.lookAt(mesh.position) //指向mesh对应的位置

// 渲染器Renderer ！！！！！！！！！！！！
const renderer = new THREE.WebGLRenderer({
    antialias: true, //渲染器锯齿属性,抗锯齿
}); // 创建渲染器对象

// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setPixelRatio(window.devicePixelRatio);

renderer.setClearColor(0x444444, 1); //设置背景颜色

// 设置Canvas画布尺寸.setSize()
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)

// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera,renderer.domElement)
// controls.target.set(1000, 0, 1000);
// controls.update();//update()函数内会执行camera.lookAt(controls.targe)
// 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
// controls.addEventListener('change', function() {
//     renderer.render(scene, camera)
//       // 浏览器控制台查看相机位置变化
//       console.log('camera.position',camera.position);
// })


// 渲染器渲染方法.render() 渲染器Canvas画布属性.domElement
// renderer.render(scene, camera);

// 请求动画帧window.requestAnimationFrame()
// 渲染循环
const clock = new THREE.Clock();
//创建stats对象
const stats = new Stats();
stats.setMode(0); //stats方法setMode(mode)

//创建一个对象，对象属性的值可以被GUI库创建的交互界面改变
const obj = {
    x: 30,
    y: 60,
    z: 300,
    color: 0xffffff,
    rotation: 1,
    scale: 0,
    scale1: 0,
    bool: true,
    specularColor: 0x111111
};
function render() {
    // const spt = clock.getDelta() * 1000; //毫秒
    // console.log('两帧渲染时间间隔（毫秒）',spt)
    // console.log('帧率（帧/秒）',1000/spt)
    stats.update();
    if(obj.bool){
        mesh.rotateY(0.01) //每次绕y轴旋转0.01弧度
    }
    renderer.render(scene, camera) //执行渲染操作
    requestAnimationFrame(render) //请求再次执行渲染函数render，渲染下一帧
}
render()
setTimeout(() => {

    document.getElementById('webGl').appendChild(renderer.domElement);
    document.getElementById('webGl').appendChild(stats.domElement);

    // document.body.appendChild(renderer.domElement);
}, 10);

// canvas画布宽高度动态变化
window.onresize = () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

// 不同硬件设备的屏幕的设备像素比window.devicePixelRatio值可能不同
console.log('查看当前屏幕设备像素比',window.devicePixelRatio);
// gui!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// 实例化一个gui对象 
const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '500px';
gui.domElement.style.width = '300px';

// gui增加交互界面，用来改变obj对应属性
const meshPositionFolder = gui.addFolder('模型位置');
meshPositionFolder.close()
meshPositionFolder.add(obj, 'x', 0, 200).onChange(() => {
    mesh.position.x = obj.x
}).name('用objx控制模型x坐标')
meshPositionFolder.add(mesh.position, 'x', 0, 200).name('模型x坐标');
meshPositionFolder.add(mesh.position, 'y', 0, 200).name('模型y坐标');
meshPositionFolder.add(mesh.position, 'z', 0, 200).name('模型z坐标');
meshPositionFolder.add(obj, 'scale',[-100, 0, 100]).onChange((value) => {
    mesh.position.y = value
}).name('下拉框控制y');
meshPositionFolder.add(obj, 'scale',{左: -100, 中: 0, 右: 100}).onChange((value) => {
    mesh.position.x = value
}).name('下拉框控制x');


const meshRotationFolder = gui.addFolder('模型旋转');
meshRotationFolder.close()
meshRotationFolder.add(obj, 'bool').onChange((value) => {
    console.log(value)
}).name('是否旋转');
meshRotationFolder.add(obj, 'rotation', 0, 2).onChange(() => {
    mesh.rotation.x = obj.rotation
}).name('改变旋转方向');

const ambientFolder = gui.addFolder('环境光');
ambientFolder.close()
ambientFolder.add(ambient, 'intensity', 0, 2.0).name('环境光强度').step(0.1);

const directionFolder = gui.addFolder('平行光');
directionFolder.close()
directionFolder.add(directionalLight, 'intensity', 0, 2.0).name('平行光强度');
// 平行光位置
const dirFolder2 = directionFolder.addFolder('平行光位置');
dirFolder2.add(directionalLight.position, 'x',-400,400);
dirFolder2.add(directionalLight.position, 'y',-400,400);
dirFolder2.add(directionalLight.position, 'z',-400,400);

const meshColorFolder = gui.addFolder('模型颜色');
meshColorFolder.close()
meshColorFolder.addColor(obj, 'color').onChange(() => {
    mesh.material.color.set(obj.color)
})
meshColorFolder.addColor(obj, 'specularColor').onChange((value) => {
    console.log(value)
    mesh.material.specular.set(value)
})
// 按下按钮
const isShow = ref(true)
const clickBtn = () => {
    console.log(isShow.value)
    isShow.value = !isShow.value

}
</script>

<style lang="scss" scoped>
.hide{
    width: 0;
    height: 0;
    overflow: hidden;
}
</style>